package com.topcheer.common.datasource.dynamic;

import com.topcheer.common.base.CommonConstants;
import com.topcheer.common.datasource.constants.DataSourceConstants;
import com.topcheer.common.datasource.exception.DataSourceBuilderException;
import com.topcheer.common.datasource.exception.NoDataSourceBuilderException;
import com.topcheer.common.datasource.exception.NoDataSourceKeyException;
import com.topcheer.common.datasource.holder.SimpleDataSourceInfoHolder;
import com.topcheer.common.datasource.vo.SimpleDataSourceInfo;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.jdbc.datasource.lookup.AbstractRoutingDataSource;
import org.springframework.util.StringUtils;

import javax.sql.DataSource;
import java.util.HashMap;
import java.util.Map;

/**
 * @author xutao
 * @Package com.topcheer.common.datasource.dynamic
 * @Description: ${todo}
 * @date 2020/4/3 13:36
 */
@Slf4j
public class DynamicDataSource extends AbstractRoutingDataSource {

    @Autowired(required = false)
    private DataSourceBuilder dataSourceBuilder;

    @Getter
    @Setter
    private String defaultDataSourceKey;

    @Getter
    @Setter
    private Map<Object, Object> dataSources = new HashMap<>();

    public DynamicDataSource(DataSource defaultTargetDataSource, Map<Object, Object> targetDataSources) {
        super.setDefaultTargetDataSource(defaultTargetDataSource);
        super.setTargetDataSources(targetDataSources);
        dataSources.put(CommonConstants.PRIMARY.concat("_").concat(DataSourceConstants.DATA_SOURCE_TYPE_READ_WRITE),defaultTargetDataSource);
        super.afterPropertiesSet();
    }
    @Override
    protected Object determineCurrentLookupKey() {
        checkDataSourceBuilder();
        SimpleDataSourceInfo simpleDataSourceInfo = SimpleDataSourceInfoHolder.get();
        checkDataSourceKey(simpleDataSourceInfo);
        String currDataSourceKey = this.createCurrDataSourceKey(simpleDataSourceInfo.getDataSourceKey(), simpleDataSourceInfo.getDataSourceType());
        if(dataSources.containsKey(currDataSourceKey)){
            return currDataSourceKey;
        }

        DataSource dataSource = this.dataSourceBuilder.builder(simpleDataSourceInfo.getDataSourceKey(), simpleDataSourceInfo.getDataSourceType());
        if(dataSource != null){
            if(this.refreshDataSource(currDataSourceKey, dataSource)){
                return currDataSourceKey;
            }
        }

        throw DataSourceBuilderException.newException("创建数据源[" + currDataSourceKey + "]失败！！！");
    }

    /**
     * 生成数据源key
     * @param dataSourceKey 数据源key
     * @param dataSourceType 数据源type
     * @return String
     */
    private String createCurrDataSourceKey(String dataSourceKey, String dataSourceType) {
        return "".concat(dataSourceKey).concat("_").concat(dataSourceType);
    }

    /**
     * 验证数据源信息非空
     * @param simpleDataSourceInfo 简单数据源信息
     */
    private void checkDataSourceKey(SimpleDataSourceInfo simpleDataSourceInfo){
        if(simpleDataSourceInfo == null || StringUtils.isEmpty(simpleDataSourceInfo.getDataSourceKey())){
            throw NoDataSourceKeyException.newException("当前线程中找不到租户id信息！！！");
        }
    }

    /**
     * 验证是否当前是否配置了数据源处理器
     */
    private void checkDataSourceBuilder(){
        if(this.dataSourceBuilder == null){
            throw NoDataSourceBuilderException.newException("当前程序未配置动态数据源处理器，请参考DataSourceBuilder！！！");
        }
    }

    /**
     * 根据给定的名称创建新的数据源
     * @param dataSourceKey 数据源key
     * @param dataSource 新创建的数据源
     * @return boolean
     */
    private boolean refreshDataSource(String dataSourceKey, DataSource dataSource){
        if(!StringUtils.isEmpty(dataSourceKey) && dataSource != null && this.dataSources != null){
            this.dataSources.put(dataSourceKey, dataSource);
            this.setTargetDataSources(this.dataSources);
            super.afterPropertiesSet();

            return true;
        }

        return false;
    }
}
